@page "/qr"
@using SkiaSharp
@using SkiaSharp.QrCode
@using SkiaSharp.QrCode.Image
@using SkiaSharp.Views.Blazor
@using Microsoft.Fast.Components.FluentUI
@using System.ComponentModel.DataAnnotations

@implements IDisposable;

<PageTitle>QR</PageTitle>

<h1>QR Code</h1>

<EditForm EditContext="@EditContext" OnSubmit="@OnHandleSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div style="margin-bottom: 1rem">
        <FluentCard>

            <div class="d-flex flex-row" style="margin:0.5rem">
                <label style="width: 80px;">Content</label>
                <InputText style="width: 100%;" @bind-Value="@Model.Content" />
            </div>

            <div class="d-flex flex-row" style="margin:0.5rem">
                <label style="width: 80px;">Size</label>
                <FluentNumberField @bind-Value=@Model.Size></FluentNumberField>
            </div>

        </FluentCard>
    </div>

    <div style="margin-bottom: 1rem">
        <FluentCard>

            <div class="d-flex flex-row" style="margin:0.5rem">
                <label style="width: 120px;">QuietZoneSize</label>
                <label style="width: 20px;">@Model.QuietZoneSize</label>
                <input style="width: 200px;" class="mx-1" type="range" min="0" max="10" step="1" @bind-value="@Model.QuietZoneSize" />
            </div>

            <div style="margin:0.5rem">
                <label style="width: 140px;">EccLevel</label>
                <InputSelect style="width: 200px;" @bind-Value="@Model.EccLevel">
                    @foreach (var level in Enum.GetValues(typeof(ECCLevel)))
                    {
                        <option value="@level">@level</option>
                    }
                </InputSelect>
            </div>

            <div style="margin:0.5rem">
                <label style="width: 140px;">ClearColor</label>
                <SKColorInputSelect style="width: 200px;" @bind-Value="@Model.ClearColor">
                    @foreach (var color in typeof(SKColors).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static).Select(x => (x.Name, Value: x.GetValue(Model.ClearColor))).ToArray())
                    {
                        <option value="@color.Value">@color.Name</option>
                    }
                </SKColorInputSelect>
            </div>

            <div style="margin:0.5rem">
                <label style="width: 140px;">CodeColor</label>
                <SKColorInputSelect style="width: 200px;" @bind-Value="@Model.CodeColor">
                    @foreach (var color in typeof(SKColors).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static).Select(x => (x.Name, Value: x.GetValue(Model.CodeColor))).ToArray())
                    {
                        <option value="@color.Value">@color.Name</option>
                    }
                </SKColorInputSelect>
            </div>

            <div style="margin:0.5rem">
                <label style="width: 140px;">BackgroundColor</label>
                <SKColorInputSelect style="width: 200px;" @bind-Value="@Model.BackgroundColor">
                    @foreach (var color in typeof(SKColors).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static).Select(x => (x.Name, Value: x.GetValue(Model.BackgroundColor))).ToArray())
                    {
                        <option value="@color.Value">@color.Name</option>
                    }
                </SKColorInputSelect>
            </div>

        </FluentCard>
    </div>

    <div style="margin-bottom: 1rem">
        <button type="submit" class="btn btn-primary">Refresh</button>
    </div>

</EditForm>

<!-- SkiaSharp.Views.Blazor work on WebAssembly workload. You need `dotnet workload install wasm-tools` before run Blazor WASM. -->
<!-- When using @ref, `width=@Model.Size height=@Model.Size` ignored. Set static value instead. -->
@*<SKCanvasView width="@Model.Size" height="@Model.Size" @ref="CanvasView" OnPaintSurface="OnPaintSurfaceQr" />*@
<SKCanvasView width="2048" height="2048" @ref="CanvasView" OnPaintSurface="OnPaintSurfaceQr" />

@code {
    private EditContext EditContext { get; set; } = default!; // Autoupdate
    private QrCodeModel Model { get; set; } = new QrCodeModel();
    private SKCanvasView? CanvasView { get; set; }

    protected override void OnInitialized()
    {
        EditContext = new EditContext(Model);
        EditContext.OnFieldChanged += OnEditContextFiledChanged;
        base.OnInitialized();
    }

    void OnEditContextFiledChanged(object? sender, FieldChangedEventArgs e)
    {
        OnHandleSubmit();
    }

    void OnHandleSubmit()
    {
        CanvasView?.Invalidate(); // re-render SKCanvasView
    }

    void OnPaintSurfaceQr(SKPaintSurfaceEventArgs e)
    {
        var content = Model.Content;

        var canvas = e.Surface.Canvas;
        canvas.Clear(SKColors.Red);
        using var generator = new QRCodeGenerator();

        // Generate QrCode
        var qr = generator.CreateQrCode(content, Model.EccLevel, quietZoneSize: Model.QuietZoneSize);

        // Render to canvas
        var info = new SKImageInfo(Model.Size, Model.Size); // Make sure match with SKCanvasView width & height.
        using var surface = SKSurface.Create(info);
        canvas.Render(qr, info.Width, info.Height, Model.ClearColor, Model.CodeColor, Model.BackgroundColor);
    }

    public void Dispose()
    {
        CanvasView?.Dispose();
    }

    public class QrCodeModel
    {
        [Required]
        public string Content { get; set; } = "https://github.com/guitarrapc/SkiaSharp.QrCode";
        [Required]
        [Range(100, 4096)]
        public int Size { get; set; } = 512;
        [Range(0, 10)]
        public int QuietZoneSize { get; set; } = 4;
        public ECCLevel EccLevel { get; set; } = ECCLevel.M;
        public SKColor ClearColor { get; set; } = SKColors.Transparent;
        public SKColor CodeColor { get; set; } = SKColors.Black;
        public SKColor BackgroundColor { get; set; } = SKColors.White;
    }
}

